package utils;

import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Vector;

import nanoxml.XMLElement;
import client.GameSettings;
import client.History;
import client.Move;

import commands.Commands;

import enums.PlayerColor;


/**
 * A table, which is a specific game between two players
 */
public class Table extends Observable implements ITransmittable  {

	private static final String ATTR_NAME_TABLE_NUMBER = "TableNumber";
	private static final String ATTR_NAME_OWNER_IP = "OwnerIP";
	private static final String ATTR_NAME_OWNER_NAME = "OwenrUsername";
	private static final String ATTR_NAME_CURRENT_PLAYER = "CurrentPlayer";
	private static final String ATTR_NAME_GAME_STATE = "GameState";
	private static final String ATTR_NAME_OTHER_PLAYER_USERNAME = "OtherPlayerUsername";
	
	public static final int NOT_PLAYING = 0;
	public static final int PLAYING = 1;
	
	private static final int NUM_OF_PLAYERS = 2;
	
	private String ownerIP = null;
	private String owenrUsername = null;
	private String otherPlayerUsername = null;
	private int tableNumber;
	private PlayerList playerList;
	private PlayerColor currentPlayer = null;
	private int gameState = 0;
	private GameSettings gameSettings = null;
	private History history = null;
	

	public Table (int tableNumber, User theUser , String ownerIP , PlayerColor color, GameSettings gameSettings) {
		this.tableNumber = tableNumber;
		this.ownerIP = ownerIP;
		this.owenrUsername = theUser.getUsername();
		this.gameSettings = gameSettings;
		
		currentPlayer = color;
		playerList = new PlayerList ();
		playerList.addPlayer (theUser , color);
		history = new History(); //false);
	}
	
	public Table (Table sourceTable) {
		this.tableNumber = sourceTable.tableNumber;
		this.ownerIP = sourceTable.ownerIP;
		this.owenrUsername = sourceTable.owenrUsername;
		this.currentPlayer = sourceTable.currentPlayer;
		this.gameState = sourceTable.gameState;
		this.gameSettings = sourceTable.gameSettings;
		
		history = new History(sourceTable.history);
		
		playerList = new PlayerList (sourceTable.getPlayerList());
	}
	
	@SuppressWarnings("unchecked")
	public Table (XMLElement message) {
		this.tableNumber = message.getIntAttribute(ATTR_NAME_TABLE_NUMBER);
		this.ownerIP = message.getStringAttribute(ATTR_NAME_OWNER_IP);
		this.owenrUsername = message.getStringAttribute(ATTR_NAME_OWNER_NAME);
		this.currentPlayer = PlayerColor.Convert(message.getIntAttribute(ATTR_NAME_CURRENT_PLAYER));
		this.gameState = message.getIntAttribute(ATTR_NAME_GAME_STATE);
		this.otherPlayerUsername = message.getStringAttribute(ATTR_NAME_OTHER_PLAYER_USERNAME);
		
		Enumeration<XMLElement> e = message.enumerateChildren();
		while (e.hasMoreElements()) {
			XMLElement childMessage = e.nextElement();

			if (childMessage.getName().equals(Commands.PLAYER_LIST)) {
				playerList = new PlayerList(childMessage);
			}
			else if (childMessage.getName().equals(Commands.GAME_SETTINGS)) {
				gameSettings = new GameSettings(childMessage);
			}
			else if (childMessage.getName().equals(Commands.HISTORY)) {
				history = new History(childMessage); //, currentPlayer != PlayerColor.RED);
			}
		}
	}
	
	public String toString () {
		StringBuffer sb = new StringBuffer (tableNumber);
	
		Vector<Player> players = playerList.getPlayers();
		for (int i = 0; i < players.size(); i++) {
	
		    Player player = (Player)players.get(i);
		    sb.append (player.getPlayerName());
		    if (i < players.size() - 1)
		        sb.append (", ");	
		}
	
		return sb.toString();
	}
	
	public XMLElement toXML(){

		XMLElement message = new XMLElement ();
		message.setName(Commands.TABLE);
		
		message.setIntAttribute(ATTR_NAME_TABLE_NUMBER, tableNumber);
		message.setAttribute(ATTR_NAME_OWNER_IP , ownerIP);
		message.setAttribute(ATTR_NAME_OWNER_NAME , owenrUsername);
		message.setAttribute(ATTR_NAME_CURRENT_PLAYER , currentPlayer.ordinal());
		message.setAttribute(ATTR_NAME_GAME_STATE , gameState);
		
		if (otherPlayerUsername != null)
		{
			message.setAttribute(ATTR_NAME_OTHER_PLAYER_USERNAME, otherPlayerUsername);
		}
		
		XMLElement playerListElement = playerList.toXML();
		message.addChild (playerListElement);
		
		XMLElement elementGameSettings = gameSettings.toXML();
		message.addChild (elementGameSettings);

		XMLElement elementHistory = history.toXML();
		message.addChild (elementHistory);

		return message;
	}
	
	public boolean addPlayer (User theUser) {
		return playerList.addPlayer (theUser);
	}
	
	public boolean addPlayer (User theUser, PlayerColor color) {
		return playerList.addPlayer (theUser,color);
	}

	public boolean removePlayer(String playerName)
	{
		return playerList.removePlayer(playerName);
	}
	
	public int getTableNum () {
		return tableNumber;
	}

	public PlayerList getPlayerList () {
	    return playerList;
	}

	public List<String> getPlayingPlayersNames()
	{
		List<String> listPlayingPlayersNames = new LinkedList<String>();
		
		listPlayingPlayersNames.add(getOwnerUsername());
		listPlayingPlayersNames.add(getOtherPlayerUsername());
		
		return listPlayingPlayersNames;
	}
	
	public void setPlayerList (PlayerList playerList) {
	    this.playerList = playerList;
	}

	public boolean containsPlayer (String user) {
		return (playerList.containsPlayer(user));
	}

	public String getOwnerUsername () {
		return owenrUsername;
	}

	public void refreshObservers () {
		setChanged();
		notifyObservers();
	}
	public void setOwnerIP (String ip) {
		ownerIP = ip;
	}

	public String getOwnerIP() {
		return ownerIP;
	}
	
	public boolean isReadyToStart() {
		int counter = 0;
		Vector<Player> players = playerList.getPlayers();
		for (Player player : players) {
			if (player.getPlayerState() == Player.PLAYER_STATE_READY_TO_START) {
				counter++;
				
				if (counter > NUM_OF_PLAYERS)
				{
					break;
				}
			}
		}
		return (counter == NUM_OF_PLAYERS); 
	}
	
	public void setGameState(int state) {
		gameState = state;
	}
	
	public int getGameState() {
		return gameState;
	}
	
	public PlayerColor getCurrentPlayer() {
		return currentPlayer;
	}
	
	public void moveTurn() {
		currentPlayer = PlayerColor.flipColor(currentPlayer);
	}

	public GameSettings getGameSettings()
	{
		return gameSettings;
	}
	
	public String getOtherPlayerUsername()
	{
		return otherPlayerUsername;
	}
	
	public void setOtherPlayerUsername(String newOtherPlayerUsername)
	{
		otherPlayerUsername = newOtherPlayerUsername; 
	}
	
	public boolean isPlayerOwner(Player player)
	{
		return player.getPlayerName().equals(getOwnerUsername());
	}
	
	public boolean isPlayerOwner(String playerName)
	{
		return playerName.equals(getOwnerUsername());
	}
	
	public void addMoveToHistory(Move moveToAdd)
	{
		history.addMove(moveToAdd);
	}
	
	public List<String> getHistoryStrings()
	{
		return history.getMovesStrings();
	}
}
